/*
 * JukeboxProperties.java
 *
 * Created on March 3, 2005, 8:40 AM
 */
package com.bff.mpd.musicjukebox.lib;

import com.bff.bjj.AbstractJukeboxProperties;
import com.bff.mpd.utils.Utils;
import org.bff.javampd.*;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDPlayerException;
import org.bff.javampd.monitor.MPDStandAloneMonitor;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author bill
 */
public class JukeboxProperties extends AbstractJukeboxProperties {

    //singleton playlist---will have to do for now
    private MPDPlaylist playlist;
    private MPDPlayer player;
    private MPDDatabase database;
    private MPDAdmin admin;
    private MPD mpd;
    private MPDStandAloneMonitor statusMonitor;
    private int mpdPort;
    private String mpdServer;
    private String mpdPassword;
    private boolean showGuitarPanel;
    private boolean showTableImage;
    private boolean checkForUpdate;
    private static boolean stopOnExit;
    private boolean useFileNameForUnknown;
    private static Exception startupException;
    private static final String PROP_MPD_SERVER = "mpd.server";
    private static final String PROP_MPD_PORT = "mpd.port";
    private static final String PROP_SHOW_GUITAR = "player.guitarpanel";
    private static final String PROP_MPD_PASSWORD = "mpd.password";
    private static final String PROP_SHOW_TABLE_IMAGE = "table.image";
    private static final String PROP_EXIT_STOP = "exit.stop";
    private static final String PROP_USE_FILE_NAME_FOR_UNKNOWN = "use.filename";
    private static final int MPD_DEFAULT_PORT = 6600;
    private static final int MPD_MONITOR_DELAY = 1000;
    private static final String PROP_FILE = "musicjukeboxmpd.properties";
    private static final String PROP_FILE_DIR = System.getProperty("user.home")
            + System.getProperty("file.separator")
            + ".bjj";
    private static final String PROP_FILE_NAME = PROP_FILE_DIR
            + System.getProperty("file.separator")
            + PROP_FILE;
    private static final String PROP_CHECK_UPDATE = "check.update";
    private static final String PROP_INCLUDE_THE = "include.the";
    private boolean includeThe;
    private static JukeboxProperties instance;

    /**
     * Creates a new instance of JukeboxProperties
     */
    private JukeboxProperties() {
        loadProperties();
        try {
            resetMPD();
        } catch (MPDConnectionException ex) {
            Logger.getLogger(JukeboxProperties.class.getName()).log(Level.SEVERE, null, ex);
            startupException = ex;
        } catch (UnknownHostException ex) {
            Logger.getLogger(JukeboxProperties.class.getName()).log(Level.SEVERE, null, ex);
            startupException = ex;
        }
    }

    public static synchronized JukeboxProperties getInstance() {
        if (instance == null) {
            instance = new JukeboxProperties();
        }
        return instance;
    }

    public boolean exists() {
        File propFile = new File(PROP_FILE_NAME);
        if (propFile.exists()) {
            return (true);
        } else {
            //see if the old prop file is there and copy
            File oldPropFile = new File(PROP_FILE);
            if (oldPropFile.exists()) {
                new File(PROP_FILE_DIR).mkdir();
                try {
                    Utils.copyFile(oldPropFile, propFile);
                    return true;
                } catch (IOException ex) {
                    Logger.getLogger(JukeboxProperties.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            return (false);
        }
    }

    public boolean saveSettings() {
        if (saveSettings(getMpdServer(),
                getMPDPassword(),
                getMpdPort(),
                isShowGuitarPanel(),
                isShowTableImage(),
                isTrayMin(),
                isStopOnExit(),
                isCheckForUpdate(),
                isUseFileNameForUnknown(),
                isIncludeThe(),
                isTrayAlways(),
                isGroupByFolder())) {
            return (true);
        } else {
            return (false);
        }
    }

    public boolean saveSettings(String mpdServer,
                                String password,
                                int mpdPort,
                                boolean showGuitarPanel,
                                boolean showTableImage,
                                boolean minToTray,
                                boolean stopOnExit,
                                boolean checkForUpdate,
                                boolean useFileNameForUnknown,
                                boolean isIncludeThe,
                                boolean trayAlways,
                                boolean groupByFolder) {

        try {
            Properties props = new Properties();
            props.setProperty(PROP_MPD_SERVER, mpdServer);
            props.setProperty(PROP_MPD_PORT, Integer.toString(mpdPort));
            props.setProperty(PROP_SHOW_GUITAR, Boolean.toString(showGuitarPanel));
            props.setProperty(PROP_SHOW_TABLE_IMAGE, Boolean.toString(showTableImage));
            props.setProperty(PROP_MIN_TRAY, Boolean.toString(minToTray));
            props.setProperty(PROP_ALWAYS_TRAY, Boolean.toString(trayAlways));
            props.setProperty(PROP_EXIT_STOP, Boolean.toString(stopOnExit));
            props.setProperty(PROP_CHECK_UPDATE, Boolean.toString(checkForUpdate));
            props.setProperty(PROP_INCLUDE_THE, Boolean.toString(isIncludeThe));
            props.setProperty(PROP_GROUP_FOLDER, Boolean.toString(groupByFolder));
            if (password != null) {
                props.setProperty(PROP_MPD_PASSWORD, password);
            }
            props.setProperty(PROP_USE_FILE_NAME_FOR_UNKNOWN, Boolean.toString(useFileNameForUnknown));
            saveMusicProperties(props);
        } catch (Exception e) {
            e.printStackTrace();
            return (false);

        }
        return (true);
    }

    private void saveMusicProperties(Properties props) throws Exception {
        File dir = new File(PROP_FILE_DIR);
        if (!dir.exists()) {
            dir.mkdir();
        }

        FileOutputStream outFile = null;
        try {
            outFile = new FileOutputStream(PROP_FILE_NAME);
            props.store(outFile, null);
        } catch (Exception e) {
            throw e;
        } finally {
            outFile.close();
        }
    }

    private void loadProperties() {
        try {
            FileInputStream inFile = new FileInputStream(PROP_FILE_NAME);
            Properties props = new Properties();
            props.load(inFile);
            String mpdPortString = null;
            //setClientType(Integer.parseInt(props.getProperty(PROP_CLIENT_TYPE)));
            setShowGuitarPanel(Boolean.valueOf(props.getProperty(PROP_SHOW_GUITAR)));
            setShowTableImage(Boolean.valueOf(props.getProperty(PROP_SHOW_TABLE_IMAGE)));
            setTrayMin(Boolean.valueOf(props.getProperty(PROP_MIN_TRAY, "false")));
            setTrayAlways(Boolean.valueOf(props.getProperty(PROP_ALWAYS_TRAY, "false")));
            setCheckForUpdate(Boolean.valueOf(props.getProperty(PROP_CHECK_UPDATE, "true")));
            setIncludeThe(Boolean.valueOf(props.getProperty(PROP_INCLUDE_THE, "false")));
            setStopOnExit(Boolean.valueOf(props.getProperty(PROP_EXIT_STOP, "false")));
            setUseFileNameForUnknown(Boolean.valueOf(props.getProperty(PROP_USE_FILE_NAME_FOR_UNKNOWN, "true")));
            mpdPortString = props.getProperty(PROP_MPD_PORT);
            setMpdServer(props.getProperty(PROP_MPD_SERVER));
            setMPDPassword(props.getProperty(PROP_MPD_PASSWORD));
            setGroupByFolder(Boolean.valueOf(props.getProperty(PROP_GROUP_FOLDER, "false")));
            if (mpdPortString == null) {
                setMpdPort(MPD_DEFAULT_PORT);
            } else {
                setMpdPort(Integer.parseInt(mpdPortString));
            }
        } catch (Exception e) {
            setMpdPort(MPD_DEFAULT_PORT);
        }
    }

    public String getMpdServer() {
        return mpdServer;
    }

    public void setMpdServer(String mpdServer) {
        this.mpdServer = mpdServer;
    }

    public int getMpdPort() {
        return mpdPort;
    }

    public void setMpdPort(int mpdPort) {
        this.mpdPort = mpdPort;
    }

    public MPDPlaylist getPlaylist() {
        return playlist;
    }

    public MPDPlayer getPlayer() {
        return player;
    }

    public MPD getMPD() {
        return mpd;
    }

    public MPDStandAloneMonitor getMPDMonitor() {
        return (statusMonitor);
    }

    public boolean showGuitarPanel() {
        JukeboxProperties jp = JukeboxProperties.getInstance();
        jp.loadProperties();
        return (jp.isShowGuitarPanel());
    }

    public final void kill() {
        try {
            getMpd().close();
        } catch (Exception e) {
        }
        try {
            player.stop();
        } catch (MPDConnectionException ex) {
            Logger.getLogger(JukeboxProperties.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MPDPlayerException ex) {
            Logger.getLogger(JukeboxProperties.class.getName()).log(Level.SEVERE, null, ex);
        }
        player = null;
        playlist = null;
    }

    public void resetMPD() throws UnknownHostException, MPDConnectionException {
        if (isUsePassword()) {
            setMpd(new MPD(getMpdServer(), getMpdPort(), getMPDPassword()));
        } else {
            setMpd(new MPD(getMpdServer(), getMpdPort()));
        }
        player = getMPD().getMPDPlayer();
        playlist = getMPD().getMPDPlaylist();
        admin = getMPD().getMPDAdmin();
        database = getMPD().getMPDDatabase();
        statusMonitor = new MPDStandAloneMonitor(getMPD(), MPD_MONITOR_DELAY);
    }

    public boolean isShowGuitarPanel() {
        return showGuitarPanel;
    }

    public void setShowGuitarPanel(boolean showGuitarPanel) {
        this.showGuitarPanel = showGuitarPanel;
    }

    public String getMPDPassword() {
        return mpdPassword;
    }

    public void setMPDPassword(String password) {
        this.mpdPassword = password;
    }

    public boolean isShowTableImage() {
        return showTableImage;
    }

    public void setShowTableImage(boolean aShowTableImage) {
        showTableImage = aShowTableImage;
    }

    /**
     * @return the stopOnExit
     */
    public boolean isStopOnExit() {
        return stopOnExit;
    }

    /**
     * @param stop the stopOnExit to set
     */
    public void setStopOnExit(boolean stop) {
        stopOnExit = stop;
    }

    /**
     * @return the database
     */
    public MPDDatabase getDatabase() {
        return database;
    }

    /**
     * @param aDatabase the database to set
     */
    public void setDatabase(MPDDatabase aDatabase) {
        database = aDatabase;
    }

    /**
     * @return the admin
     */
    public MPDAdmin getAdmin() {
        return admin;
    }

    /**
     * @param aAdmin the admin to set
     */
    public void setAdmin(MPDAdmin aAdmin) {
        admin = aAdmin;
    }

    /**
     * @return the mpd
     */
    private MPD getMpd() {
        return mpd;
    }

    /**
     * @param mpd the mpd to set
     */
    public void setMpd(MPD mpd) {
        this.mpd = mpd;
    }

    /**
     * @return the checkForUpdate
     */
    public boolean isCheckForUpdate() {
        return checkForUpdate;
    }

    /**
     * @param aCheckForUpdate the checkForUpdate to set
     */
    public void setCheckForUpdate(boolean aCheckForUpdate) {
        checkForUpdate = aCheckForUpdate;
    }

    /**
     * @return the useFileNameForUnknown
     */
    public boolean isUseFileNameForUnknown() {
        return useFileNameForUnknown;
    }

    /**
     * @param aUseFileNameForUnknown the useFileNameForUnknown to set
     */
    public void setUseFileNameForUnknown(boolean aUseFileNameForUnknown) {
        useFileNameForUnknown = aUseFileNameForUnknown;
    }

    public void setIncludeThe(boolean includeThe) {
        this.includeThe = includeThe;
    }

    public boolean isIncludeThe() {
        return this.includeThe;
    }

    private boolean isUsePassword() {
        return getMPDPassword() != null;
    }

    /**
     * If there were any exceptions thrown at creation time you can find them here.
     *
     * @return the exception that prevented startup
     */
    public static Exception getStartupException() {
        return startupException;
    }
}
